Micron Document
πŸŽ–οΈGitΠ―Ρ€Π°πŸŽ–οΈ


Displaying Raw β€’ Download

feature/firmware/src/commonMain/kotlin/org/meshtastic/feature/firmware/ota/dfu/LegacyDfuProtocol.kt 2d20cd8a4708e2ef66e98d5259f3a97ec93f240a (2d20cd8a) Text, 13.53 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tf0883e@fileTb4b4b4:Te6edf3SuppressTb4b4b4(Ta5d6ff"Ta5d6ffMagicNumberTa5d6ff"Tb4b4b4)

Tff7b72package T7ee787org.meshtastic.feature.firmware.ota.dfu

Tff7b72import T7ee787org.meshtastic.core.ble.BleConnectionState
Tff7b72import T7ee787kotlin.uuid.Uuid

T8b949e// ---------------------------------------------------------------------------
T8b949e// Nordic Legacy DFU – additional service characteristic UUIDs
T8b949e// (Service + Control Point are declared in `LegacyDfuUuids` in
T8b949e// SecureDfuProtocol.kt β€” they're shared with the Phase-1 buttonless trigger.)
T8b949e// ---------------------------------------------------------------------------

T8b949e/** Packet characteristic β€” accepts WRITE_NO_RESPONSE for image sizes, init data, and firmware bytes. */
Tff7b72internal Tff7b72val Te6edf3LEGACY_DFU_PACKET_UUIDTb4b4b4: Te6edf3Uuid Tff7b72= Te6edf3UuidTb4b4b4.Te6edf3parseTb4b4b4(Ta5d6ff"Ta5d6ff00001532-1212-EFDE-1523-785FEABCD123Ta5d6ff"Tb4b4b4)

T8b949e/**
* DFU Version characteristic β€” optional; uint16 LE giving bootloader DFU version. Used to gate the extended init-packet
* flow (β‰₯ 5 β‡’ START/COMPLETE bracket; ≀ 4 β‡’ unsupported old SDK).
*/
Tff7b72internal Tff7b72val Te6edf3LEGACY_DFU_VERSION_UUIDTb4b4b4: Te6edf3Uuid Tff7b72= Te6edf3UuidTb4b4b4.Te6edf3parseTb4b4b4(Ta5d6ff"Ta5d6ff00001534-1212-EFDE-1523-785FEABCD123Ta5d6ff"Tb4b4b4)

T8b949e// ---------------------------------------------------------------------------
T8b949e// Protocol opcodes (Nordic SDK 11/12 / Adafruit BLEDfu)
T8b949e// ---------------------------------------------------------------------------

Tff7b72internal Tff7b72object T56d364LegacyDfuOpcode Tb4b4b4{
Tff7b72const Tff7b72val Te6edf3START_DFUTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x01
Tff7b72const Tff7b72val Te6edf3INIT_DFU_PARAMSTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x02
Tff7b72const Tff7b72val Te6edf3RECEIVE_FIRMWARE_IMAGETb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x03
Tff7b72const Tff7b72val Te6edf3VALIDATETb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x04
Tff7b72const Tff7b72val Te6edf3ACTIVATE_AND_RESETTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x05
Tff7b72const Tff7b72val Te6edf3RESETTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x06
Tff7b72const Tff7b72val Te6edf3PACKET_RECEIPT_NOTIF_REQTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x08

T8b949e/** Prefix on every Control-Point response notification. */
Tff7b72const Tff7b72val Te6edf3RESPONSE_CODETb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x10

T8b949e/** Prefix on every Packet-Receipt notification (carries `[bytes_received_u32_le]`). */
Tff7b72const Tff7b72val Te6edf3PACKET_RECEIPTTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x11

T8b949e/** Sub-opcode of `INIT_DFU_PARAMS`: marks beginning of init-packet stream. */
Tff7b72const Tff7b72val Te6edf3INIT_PARAMS_STARTTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x00

T8b949e/** Sub-opcode of `INIT_DFU_PARAMS`: marks end of init-packet stream. */
Tff7b72const Tff7b72val Te6edf3INIT_PARAMS_COMPLETETb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x01
Tb4b4b4}

T8b949e/**
* `START_DFU` image-type bitmask. Meshtastic only ever ships application updates over OTA, so the transport hard-codes
* [APPLICATION].
*/
Tff7b72internal Tff7b72object T56d364LegacyDfuImageType Tb4b4b4{
Tff7b72const Tff7b72val Te6edf3SOFT_DEVICETb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x01
Tff7b72const Tff7b72val Te6edf3BOOTLOADERTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x02
Tff7b72const Tff7b72val Te6edf3APPLICATIONTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x04
Tb4b4b4}

T8b949e/** Result codes returned in the third byte of a response notification. */
Tff7b72internal Tff7b72object T56d364LegacyDfuStatus Tb4b4b4{
Tff7b72const Tff7b72val Te6edf3SUCCESSTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x01
Tff7b72const Tff7b72val Te6edf3INVALID_STATETb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x02
Tff7b72const Tff7b72val Te6edf3NOT_SUPPORTEDTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x03
Tff7b72const Tff7b72val Te6edf3DATA_SIZE_EXCEEDS_LIMITTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x04
Tff7b72const Tff7b72val Te6edf3CRC_ERRORTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x05
Tff7b72const Tff7b72val Te6edf3OPERATION_FAILEDTb4b4b4: Tffa657Byte Tff7b72= T79c0ff0Te6edf3x06

Tff7b72fun Td2a8ffdescribeTb4b4b4(Te6edf3statusTb4b4b4: Tffa657ByteTb4b4b4)Tb4b4b4: Tffa657String Tff7b72= Tff7b72when Tb4b4b4(Te6edf3statusTb4b4b4) Tb4b4b4{
Te6edf3SUCCESS Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffSUCCESSTa5d6ff"
Te6edf3INVALID_STATE Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffINVALID_STATETa5d6ff"
Te6edf3NOT_SUPPORTED Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffNOT_SUPPORTEDTa5d6ff"
Te6edf3DATA_SIZE_EXCEEDS_LIMIT Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffDATA_SIZE_EXCEEDS_LIMITTa5d6ff"
Te6edf3CRC_ERROR Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffCRC_ERRORTa5d6ff"
Te6edf3OPERATION_FAILED Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffOPERATION_FAILEDTa5d6ff"
Tff7b72else Tff7b72-Tff7b72> Ta5d6ff"Ta5d6ffUNKNOWN(0xTffd700${Te6edf3statusTb4b4b4.Te6edf3toUByteTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff1T79c0ff6Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff2Tb4b4b4, Ta5d6ff'0'Tb4b4b4)Tffd700}Ta5d6ff)Ta5d6ff"
Tb4b4b4}
Tb4b4b4}

T8b949e// ---------------------------------------------------------------------------
T8b949e// Response parsing
T8b949e// ---------------------------------------------------------------------------

T8b949e/** Parsed notification from the Legacy DFU Control Point characteristic. */
Tff7b72internal Tff7b72sealed Tff7b72class T56d364LegacyDfuResponse Tb4b4b4{

T8b949e/** `[0x10, requestOpcode, 0x01]` β€” request succeeded. */
Tff7b72data Tff7b72class T56d364SuccessTb4b4b4(Tff7b72val Te6edf3requestOpcodeTb4b4b4: Tffa657ByteTb4b4b4) Tb4b4b4: Te6edf3LegacyDfuResponseTb4b4b4(Tb4b4b4)

T8b949e/** `[0x10, requestOpcode, status]` where `status != 0x01` β€” device rejected the request. */
Tff7b72data Tff7b72class T56d364FailureTb4b4b4(Tff7b72val Te6edf3requestOpcodeTb4b4b4: Tffa657ByteTb4b4b4, Tff7b72val Te6edf3statusTb4b4b4: Tffa657ByteTb4b4b4) Tb4b4b4: Te6edf3LegacyDfuResponseTb4b4b4(Tb4b4b4)

T8b949e/** `[0x11, bytes_received_u32_le]` β€” periodic packet-receipt notification. */
Tff7b72data Tff7b72class T56d364PacketReceiptTb4b4b4(Tff7b72val Te6edf3bytesReceivedTb4b4b4: Tffa657LongTb4b4b4) Tb4b4b4: Te6edf3LegacyDfuResponseTb4b4b4(Tb4b4b4)

T8b949e/** Unrecognised bytes β€” logged, surfaced as a protocol error. */
Tff7b72data Tff7b72class T56d364UnknownTb4b4b4(Tff7b72val Te6edf3rawTb4b4b4: Te6edf3ByteArrayTb4b4b4) Tb4b4b4: Te6edf3LegacyDfuResponseTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72override Tff7b72fun Td2a8ffequalsTb4b4b4(Te6edf3otherTb4b4b4: Tffa657Any?Tb4b4b4) Tff7b72= Te6edf3other Tff7b72is Te6edf3Unknown Tff7b72&Tff7b72& Te6edf3rawTb4b4b4.Te6edf3contentEqualsTb4b4b4(Te6edf3otherTb4b4b4.Te6edf3rawTb4b4b4)

Tff7b72override Tff7b72fun Td2a8ffhashCodeTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3rawTb4b4b4.Te6edf3contentHashCodeTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tff7b72companion Tff7b72object Tb4b4b4{
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffReturnCountTa5d6ff"Tb4b4b4)
Tff7b72fun Td2a8ffparseTb4b4b4(Te6edf3dataTb4b4b4: Te6edf3ByteArrayTb4b4b4)Tb4b4b4: Te6edf3LegacyDfuResponse Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3dataTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72return Te6edf3UnknownTb4b4b4(Te6edf3dataTb4b4b4)
Tff7b72return Tff7b72when Tb4b4b4(Te6edf3dataTff7b72[T79c0ff0Tff7b72]Tb4b4b4) Tb4b4b4{
Te6edf3LegacyDfuOpcodeTb4b4b4.Te6edf3RESPONSE_CODE Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3dataTb4b4b4.Te6edf3size Tff7b72< T79c0ff3Tb4b4b4) Tff7b72return Te6edf3UnknownTb4b4b4(Te6edf3dataTb4b4b4)
Tff7b72val Te6edf3requestOpcode Tff7b72= Te6edf3dataTff7b72[T79c0ff1Tff7b72]
Tff7b72val Te6edf3status Tff7b72= Te6edf3dataTff7b72[T79c0ff2Tff7b72]
Tff7b72if Tb4b4b4(Te6edf3status Tff7b72=Tff7b72= Te6edf3LegacyDfuStatusTb4b4b4.Te6edf3SUCCESSTb4b4b4) Tb4b4b4{
Te6edf3SuccessTb4b4b4(Te6edf3requestOpcodeTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3FailureTb4b4b4(Te6edf3requestOpcodeTb4b4b4, Te6edf3statusTb4b4b4)
Tb4b4b4}
Tb4b4b4}

Te6edf3LegacyDfuOpcodeTb4b4b4.Te6edf3PACKET_RECEIPT Tff7b72-Tff7b72> Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3dataTb4b4b4.Te6edf3size Tff7b72< T79c0ff5Tb4b4b4) Tff7b72return Te6edf3UnknownTb4b4b4(Te6edf3dataTb4b4b4)
Tff7b72val Te6edf3bytes Tff7b72=
Tb4b4b4(Te6edf3dataTff7b72[T79c0ff1Tff7b72]Tb4b4b4.Te6edf3toLongTb4b4b4(Tb4b4b4) Te6edf3and T79c0ff0Te6edf3xFFTb4b4b4) Te6edf3or
Tb4b4b4(Tb4b4b4(Te6edf3dataTff7b72[T79c0ff2Tff7b72]Tb4b4b4.Te6edf3toLongTb4b4b4(Tb4b4b4) Te6edf3and T79c0ff0Te6edf3xFFTb4b4b4) Te6edf3shl T79c0ff8Tb4b4b4) Te6edf3or
Tb4b4b4(Tb4b4b4(Te6edf3dataTff7b72[T79c0ff3Tff7b72]Tb4b4b4.Te6edf3toLongTb4b4b4(Tb4b4b4) Te6edf3and T79c0ff0Te6edf3xFFTb4b4b4) Te6edf3shl T79c0ff1T79c0ff6Tb4b4b4) Te6edf3or
Tb4b4b4(Tb4b4b4(Te6edf3dataTff7b72[T79c0ff4Tff7b72]Tb4b4b4.Te6edf3toLongTb4b4b4(Tb4b4b4) Te6edf3and T79c0ff0Te6edf3xFFTb4b4b4) Te6edf3shl T79c0ff2T79c0ff4Tb4b4b4)
Te6edf3PacketReceiptTb4b4b4(Te6edf3bytesTb4b4b4)
Tb4b4b4}

Tff7b72else Tff7b72-Tff7b72> Te6edf3UnknownTb4b4b4(Te6edf3dataTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

T8b949e// ---------------------------------------------------------------------------
T8b949e// Payload builders
T8b949e// ---------------------------------------------------------------------------

T8b949e/**
* Build the 12-byte image-sizes payload written to the Packet characteristic immediately after `START_DFU`.
*
* Layout: `[soft_device_size_u32_le, bootloader_size_u32_le, app_size_u32_le]`. Meshtastic only updates the
* application, so [softDeviceSize] and [bootloaderSize] default to 0.
*/
Tff7b72internal Tff7b72fun Td2a8fflegacyImageSizesPayloadTb4b4b4(Te6edf3appSizeTb4b4b4: Tffa657IntTb4b4b4, Te6edf3softDeviceSizeTb4b4b4: Tffa657Int Tff7b72= T79c0ff0Tb4b4b4, Te6edf3bootloaderSizeTb4b4b4: Tffa657Int Tff7b72= T79c0ff0Tb4b4b4)Tb4b4b4: Te6edf3ByteArray Tff7b72=
Te6edf3intToLeBytesTb4b4b4(Te6edf3softDeviceSizeTb4b4b4) Tff7b72+ Te6edf3intToLeBytesTb4b4b4(Te6edf3bootloaderSizeTb4b4b4) Tff7b72+ Te6edf3intToLeBytesTb4b4b4(Te6edf3appSizeTb4b4b4)

T8b949e/** Build the 3-byte `PACKET_RECEIPT_NOTIF_REQ` payload: opcode + uint16-LE PRN value. */
Tff7b72internal Tff7b72fun Td2a8fflegacyPrnRequestPayloadTb4b4b4(Te6edf3packetsTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Te6edf3ByteArray Tff7b72= Te6edf3byteArrayOfTb4b4b4(
Te6edf3LegacyDfuOpcodeTb4b4b4.Te6edf3PACKET_RECEIPT_NOTIF_REQTb4b4b4,
Tb4b4b4(Te6edf3packets Te6edf3and T79c0ff0Te6edf3xFFTb4b4b4)Tb4b4b4.Te6edf3toByteTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4(Tb4b4b4(Te6edf3packets Te6edf3ushr T79c0ff8Tb4b4b4) Te6edf3and T79c0ff0Te6edf3xFFTb4b4b4)Tb4b4b4.Te6edf3toByteTb4b4b4(Tb4b4b4)Tb4b4b4,
Tb4b4b4)

T8b949e// ---------------------------------------------------------------------------
T8b949e// Stream profiles
T8b949e// ---------------------------------------------------------------------------

T8b949e/**
* Default packet-receipt-notification interval (packets between flow-control ACKs). Higher values mean fewer
* notification round-trips per byte and therefore faster throughput, at the cost of a slightly longer recovery window
* if a packet is dropped.
*
* Capped at 10 to match Nordic's own Legacy DFU implementation, which force-limits legacy PRN to ≀10 with the comment:
* "DFU bootloaders from SDK 6.0.0 or older were unable to save incoming data to flash as fast as they are being sent …
* PRN = 10 may be the highest supported value" and treats status 6 (OPERATION_FAILED) as "data sent too fast β€” reduce
* PRN to 10 or less." The stock Adafruit bootloader shares this SDK11 flash-write path, so a higher value risks
* OPERATION_FAILED mid-stream on stock bootloaders. 10 is the safe ceiling that still batches flow-control ACKs.
*/
Tff7b72internal Tff7b72const Tff7b72val Te6edf3PRN_INTERVAL_PACKETS Tff7b72= T79c0ff1T79c0ff0

T8b949e/**
* Tighter PRN interval used only on a recovery upload that follows a mid-stream disconnect. Halving the interval
* reduces the burst depth between flow-control checkpoints. Used exclusively by [LegacyDfuStreamProfile.RECOVERY] as a
* recovery heuristic; it does not by itself prevent a bootloader-side stall.
*/
Tff7b72internal Tff7b72const Tff7b72val Te6edf3RECOVERY_PRN_INTERVAL_PACKETS Tff7b72= T79c0ff5

T8b949e/**
* Legacy upload profile. Selects the PRN interval used in BOTH the `PACKET_RECEIPT_NOTIF_REQ` request and the
* receipt-await threshold inside [org.meshtastic.feature.firmware.ota.dfu.LegacyDfuTransport.streamFirmware].
* - [NORMAL]: the healthy first-attempt transfer profile β€” fewer PRN round-trips, higher throughput.
* - [RECOVERY]: selected after a [LegacyDfuException.MidStreamDisconnect] so subsequent attempts on the same run use
* the tighter interval. A [LegacyDfuException.StaleSessionReset] alone does NOT switch the profile, since the link
* did not actually drop mid-upload.
*/
Tff7b72internal Tff7b72enum Tff7b72class T56d364LegacyDfuStreamProfileTb4b4b4(Tff7b72val Te6edf3prnIntervalPacketsTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4{
Te6edf3NORMALTb4b4b4(Te6edf3PRN_INTERVAL_PACKETSTb4b4b4)Tb4b4b4,
Te6edf3RECOVERYTb4b4b4(Te6edf3RECOVERY_PRN_INTERVAL_PACKETSTb4b4b4)Tb4b4b4,
Tb4b4b4}

T8b949e// ---------------------------------------------------------------------------
T8b949e// Exceptions
T8b949e// ---------------------------------------------------------------------------

T8b949e/**
* Errors specific to the Nordic Legacy DFU protocol. These are a subtype of [DfuException] so the existing handler
* error-path code (which catches `DfuException`) covers both protocols.
*/
Tff7b72sealed Tff7b72class T56d364LegacyDfuExceptionTb4b4b4(Te6edf3messageTb4b4b4: Tffa657StringTb4b4b4, Te6edf3causeTb4b4b4: Te6edf3Throwable? Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4: Te6edf3DfuExceptionTb4b4b4(Te6edf3messageTb4b4b4, Te6edf3causeTb4b4b4) Tb4b4b4{
T8b949e/** Device returned a non-success status for a given opcode. */
Tff7b72class T56d364ProtocolErrorTb4b4b4(Tff7b72val Te6edf3requestOpcodeTb4b4b4: Tffa657ByteTb4b4b4, Tff7b72val Te6edf3statusTb4b4b4: Tffa657ByteTb4b4b4) Tb4b4b4:
Te6edf3LegacyDfuExceptionTb4b4b4(
Ta5d6ff"Ta5d6ffLegacy DFU protocol error: opcode=0xTffd700${Te6edf3requestOpcodeTb4b4b4.Te6edf3toUByteTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(T79c0ff1T79c0ff6Tb4b4b4)Tb4b4b4.Te6edf3padStartTb4b4b4(T79c0ff2Tb4b4b4, Ta5d6ff'0'Tb4b4b4)Tffd700}Ta5d6ff Ta5d6ff" Tff7b72+
Ta5d6ff"Ta5d6ffstatus=Tffd700${Te6edf3LegacyDfuStatusTb4b4b4.Te6edf3describeTb4b4b4(Te6edf3statusTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4,
Tb4b4b4)

T8b949e/** Bootloader exposes DFU Version characteristic with a value below 5 (Nordic SDK ≀ 6). Unsupported. */
Tff7b72class T56d364UnsupportedBootloaderTb4b4b4(Te6edf3versionTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4:
Te6edf3LegacyDfuExceptionTb4b4b4(
Ta5d6ff"Ta5d6ffLegacy DFU bootloader version Tffd700$Te6edf3versionTa5d6ff is too old (need β‰₯ 5). Please update the bootloader.Ta5d6ff"Tb4b4b4,
Tb4b4b4)

T8b949e/** Init packet ([dat]) appears to be Secure-DFU shaped (signed/CBOR), not the small legacy 14-32 B form. */
Tff7b72class T56d364InitPacketNotLegacyTb4b4b4(Te6edf3sizeTb4b4b4: Tffa657IntTb4b4b4) Tb4b4b4:
Te6edf3LegacyDfuExceptionTb4b4b4(
Ta5d6ff"Ta5d6ffInit packet is Tffd700$Te6edf3sizeTa5d6ff bytes β€” too large for Legacy DFU. Ta5d6ff" Tff7b72+
Ta5d6ff"Ta5d6ffThis .dat looks like a Secure DFU init packet; the bootloader will reject it.Ta5d6ff"Tb4b4b4,
Tb4b4b4)

T8b949e/** Bytes received reported by device differs from bytes sent past last PRN window. */
Tff7b72class T56d364PacketReceiptMismatchTb4b4b4(Te6edf3expectedTb4b4b4: Tffa657LongTb4b4b4, Te6edf3actualTb4b4b4: Tffa657LongTb4b4b4) Tb4b4b4:
Te6edf3LegacyDfuExceptionTb4b4b4(Ta5d6ff"Ta5d6ffPacket receipt mismatch: expected Tffd700$Te6edf3expectedTa5d6ff bytes received, device reports Tffd700$Te6edf3actualTa5d6ff"Tb4b4b4)

T8b949e/**
* START_DFU was rejected with INVALID_STATE because the bootloader still holds state from an interrupted session.
* The current connection is closed without attempting RESET; SecureDfuHandler performs a bounded reset-prime over a
* fresh connection before retrying.
*/
Tff7b72class T56d364StaleSessionReset Tb4b4b4:
Te6edf3LegacyDfuExceptionTb4b4b4(
Ta5d6ff"Ta5d6ffBootloader rejected START with INVALID_STATE (leftover from an interrupted flash); reset and retrying.Ta5d6ff"Tb4b4b4,
Tb4b4b4)

T8b949e/**
* The BLE link dropped while firmware bytes were in flight. Carries the host in-flight offset (the end of the write
* the host had dispatched or was in flight at the moment of the drop) so the retry coordinator can distinguish a
* mid-stream failure (which switches subsequent Legacy uploads to [LegacyDfuStreamProfile.RECOVERY]) from a
* handshake/connect failure (which does not).
*
* [bytesSent] is the end offset of the host write currently dispatched or in flight. It may include the current
* chunk when the disconnect occurs during `service.write()`. It does NOT prove the host stack accepted the chunk,
* and it does NOT prove the bootloader received or committed it. [lastConfirmedBytes] is the authoritative
* PRN-confirmed checkpoint (the last byte the bootloader explicitly acknowledged); `-1` means no PRN was received
* before the drop. Do not treat [bytesSent] as confirmed device progress.
*
* [connectionState] is the typed [BleConnectionState] observed at the moment of the drop (always
* [BleConnectionState.Disconnected]); the message renders it via `toString()` only for human-readable logging.
*
* The optional [cause] carries the underlying operational write exception when classification was triggered by a
* failed BLE write on an already-disconnected link. Watcher-originated disconnects (where the state-flow watcher
* detected the drop independently) may have no cause.
*
* Typed β€” callers must NOT parse the message to detect a mid-stream drop.
*/
Tff7b72class T56d364MidStreamDisconnectTb4b4b4(
Tff7b72val Te6edf3bytesSentTb4b4b4: Tffa657IntTb4b4b4,
Tff7b72val Te6edf3totalBytesTb4b4b4: Tffa657IntTb4b4b4,
Tff7b72val Te6edf3connectionStateTb4b4b4: Te6edf3BleConnectionStateTb4b4b4,
Tff7b72val Te6edf3lastConfirmedBytesTb4b4b4: Tffa657IntTb4b4b4,
Te6edf3causeTb4b4b4: Te6edf3Throwable? Tff7b72= Tff7b72nullTb4b4b4,
Tb4b4b4) Tb4b4b4: Te6edf3LegacyDfuExceptionTb4b4b4(
Ta5d6ff"Ta5d6ffBLE link dropped mid-upload at host in-flight offset Tffd700$Te6edf3bytesSentTa5d6ff/Tffd700$Te6edf3totalBytesTa5d6ff Ta5d6ff" Tff7b72+
Ta5d6ff"Ta5d6ff(lastConfirmed=Tffd700$Te6edf3lastConfirmedBytesTa5d6ff, state=Tffd700$Te6edf3connectionStateTa5d6ff)Ta5d6ff"Tb4b4b4,
Te6edf3causeTb4b4b4,
Tb4b4b4)
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.25s